/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package carreras.entidades;

import carreras.logger.CarrerasLogger;
import carreras.negocio.NegCarrera;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;

/**
 *
 * @author Fanky10 <fanky10@gmail.com>
 */
public class Competencia extends ArrayList<Carrera>{
    public static int COMPETENCIA_LIBRE = 1;
    public static int COMPETENCIA_PRELIMINAR = 2;
    public static int COMPETENCIA_ELIMINATORIA = 3;
    public static final String[] TIPOS = new String[]{"Libre","Preliminar","Eliminatoria"};
    //independiente de la instanciacion
    public static final int NUMERO_RONDA_INICIAL = 1;//por default 1
    private int id;
    private int tipo_competicion;
    private int numero_ronda;
    public Competencia(int tipo_competicion){
        this(-1,tipo_competicion,NUMERO_RONDA_INICIAL);
    }

    public Competencia(int tipo_competicion, int numero_ronda) {
        this(-1, tipo_competicion,numero_ronda);
    }
    
    public Competencia(int id, int tipo_competicion, int numero_ronda) {
        this.id = id;
        this.tipo_competicion = tipo_competicion;
        this.numero_ronda = numero_ronda;
    }
    
    
    public String toString(){
        return TIPOS[tipo_competicion-1];
    }
    
    public void nueva_ronda(){
        this.numero_ronda++;
    }

    public int getTipo_competicion() {
        return tipo_competicion;
    }

    public int getNumero_ronda() {
        return numero_ronda;
    }

    public void setNumero_ronda(int numero_ronda) {
        this.numero_ronda = numero_ronda;
    }

    public void setTipo_competicion(int tipo_competicion) {
        this.tipo_competicion = tipo_competicion;
    }
    

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
    
    
    
    /**
     * agrega un nuevo CorredorAuto a la competencia
     * chequea primero si hay algun lugar en la carrera y de no ser asi 
     * instancia una nueva 
     * @param ca
     * @return true si se agrego false caso contrario
     */
    public boolean add(CorredorAuto ca) throws SQLException{
        if(this.isEmpty()){//estoy vacio, genero una nueva y a la goma :D
            CarrerasLogger.debug(Competencia.class, "estoy empty generando una nueva");
            Carrera c = generaCarrera();
            c.add(ca);
            return this.add(c);
        }else{
            //toma la ultima carrera generada
            Carrera c = this.getUltimaCarrera(ca);
            if(c!=null){//no encontro nada, en vez de lanzar una exception
                c.add(ca);
                return true;
            }else{
                c = generaCarrera();
                c.add(ca);
                return this.add(c);
            }
//            Carrera c = this.get(this.size()-1);//la ultima
//            if(c.isCompleta()){//genero una nueva :P
//                CarrerasLogger.debug(Competencia.class, "carrera completa generando una nueva");
//                c = generaCarrera();
//                c.add(ca);
//                return this.add(c);
//            }//chequeo que si no esta completa y que sea de la misma categoria
//            else if(c.get(0).getCorredor_auto().getCategoria().getId() == ca.getCategoria().getId()){
//                CarrerasLogger.debug(Competencia.class, "agregando a una existente");
//                c.add(ca);
//                return true;
//            }
        }
        //return false; //no lo puse agregar
    }
    /**
     * @param id_categoria
     * @return 
     * devuelve la ultima carrera no completa con esa categoria,
     * ahora se le suma el estado en esa categoria --> ganador / perdedor / sin estado
     * de no haber ninguna genera una nueva
     */
//    public Carrera getUltimaCarrera(int id_categoria) throws SQLException{
//        return getUltimaCarrera(id_categoria, CorredorAuto.ESTADO_COMPETENCIA_LIBRE);
//    }
    /*
     * devuelve la ultima carrera, si no hay ninguna retorna null
     */
    public Carrera getUltimaCarrera(CorredorAuto ca) throws SQLException{
        for(Carrera c :this){
            //si es de la misma categ y no esta completa la devuelvo
            if(!c.isCompleta() && 
                    c.get(0).getCorredor_auto().getCategoria().getId() == ca.getCategoria().getId() 
                    && c.get(0).getCorredor_auto().getEstado_competencia() == ca.getEstado_competencia()){
                //CarrerasLogger.debug(Competencia.class, "una incompleta!! de cat: "+ca.getCategoria() + " && estcomp "+ca.getEstado_competencia());
                return c;
            }
        }
        //CarrerasLogger.debug(Competencia.class, "no encontre ninguna de cat: "+ca.getCategoria() + " && estcomp "+ca.getEstado_competencia());
        //si no encontre ninguna, genero una nueva :D
        return null;
    }
    /**
     * agrega una cat. de corredores, de tal manera que
     * los de la misma categoria, aparezcan juntos (:
     * @param ccaV
     * @return
     * @throws SQLException 
     */
    public boolean addAll(CatCorredorAuto ccaV) throws SQLException{
        for(CorredorAuto ca: ccaV){
            if(!this.add(ca)){
                CarrerasLogger.warn(Competencia.class, "error agregando corredor auto: "+ca.getNumero_asignado());                
            }
                
        }
        join_ganadores_categ();
        return true;
    }
    /**
     * aqui reverifico carreras de la misma cat. con long = 2, de ser asi hace un merge
     * primero obtengo las categorias que tienen solo dos competidores
     * para esto tiene que estar ordenado por categ.
     * luego para c/categ. que ya se que solo hay dos
     * elimino el proximo, y le seteo ese mismo carril a la anterior, entonces te queda todo ordenadito (:
     */
    private void join_ganadores_categ(){
        //quizas aqui se podria reordenar...
        //pero se que lo hago antes :P
        for(int i=0;i<this.size();i++){
            Carrera c = this.get(i);
            if(!c.isEmpty() && c.size()==1){
                CarrerasLogger.debug(Competencia.class, "Carrera solitaria! buscandole amigui");
                i++;
                if(i==this.size()){
                    CarrerasLogger.debug(Competencia.class, "no hay mas para buscar :(");
                }else{
                    Carrera next = this.get(i);
                    if(!next.isEmpty() && next.size()==1 && next.getCategoria().getId() == c.getCategoria().getId()){
                        CarrerasLogger.debug(Competencia.class, "amigui encontrado! agregandoselo (:");
                        CarrilCarrera cc = next.get(0);
                        cc.setNro_carril(2);
                        c.add(cc);
                        this.remove(i);
                    }
                }
            }
        }
    }
    /**
     * TODO: ir a la base de datos y obtener la nueva carrera (:
     * @return 
     */
    private Carrera generaCarrera() throws SQLException{
        Carrera carrera = null;
        if(tipo_competicion == COMPETENCIA_LIBRE){
            carrera =  new CarreraLibre();
        }else if(tipo_competicion == COMPETENCIA_PRELIMINAR){
            carrera = new CarreraCompeticion();
        }else if(tipo_competicion == COMPETENCIA_ELIMINATORIA){
            carrera = new CarreraEliminatoria();
        }
        
        if(carrera == null){
            throw new IllegalArgumentException("argument: "+tipo_competicion+" is unknown");
        }
        
        carrera.setId(new NegCarrera().nuevaCarrera(this.id));
        return carrera;
    }
    /**
     * v1.0 stable
     * v1.1 si la carrera solo tiene un jugador lo toma como ganador y pasa a la prox. ronda
     * @return la proxima carrera a ejecutarse
     * @throws TodasCarrerasFinalizadasException
     */
    public Carrera getSiguienteCarrera() throws TodasCarrerasFinalizadasException{
        //TODO: si es de un ganador de cat. que espere a tener un ganador de la cat con =/= estado
        //si es el ganador for real lo elimina y lesto o lo deja como ganador cat ;)
        //TODO: ver que onda
        CarrerasLogger.debug(Competencia.class, "Obteniendo la prox carrera");
        for(Carrera c: this){
            if(!c.isCarreraOver() && c.size()>1)//chequear!
                return c;
        }
        throw new TodasCarrerasFinalizadasException();
    }
    
    /**
     * no se bien para que lo utilizaria pero pinta copado
     */
    public void finCarrera(){
        throw new UnsupportedOperationException("not supported yet");
    }
    /**
     * 
     */
    public void fin_competencia_preeliminar(){
        //TODO: actualizo los estados internos de los corredores, para luego saber quien corre contra quien
        for(Carrera c: this){
            for(CorredorAuto ca: c.getCatCorredorAuto()){
                if(ca.getEstado_carrera() == CarrilCarrera.ESTADO_GANADOR){
                    ca.setEstado_competencia(CorredorAuto.ESTADO_COMPETENCIA_GANADOR);
                    
                }else{
                    ca.setEstado_competencia(CorredorAuto.ESTADO_COMPETENCIA_PERDEDOR);
                }
            }
        }
    }
    
    /**
     * 
     * @return devuelve el arreglo de corredores activos
     */
    public CatCorredorAuto getCorredoresAutosActivos(){
        //CarrerasLogger.debug(Competencia.class, "corredores activos! misize "+this.size());
        final CatCorredorAuto reto = new CatCorredorAuto();
        for(Carrera c: this){
            reto.addAll(c.getCatCorredorAuto());
        }
        return reto;
    }
//    private class OrdenCategoria implements Comparator<CorredorAuto>{
//        public static final int ASC =0 ;
//        public static final int DESC = 1;
//        private int tipo_comparacion;
//        public OrdenCategoria() {
//            this.tipo_comparacion = -1;
//        }
//        public void cambia_comparacion(){
//            if(tipo_comparacion == DESC){
//                tipo_comparacion = ASC;
//            }else if(tipo_comparacion == ASC){
//                tipo_comparacion = DESC;
//            }else{
//                tipo_comparacion = ASC;
//            }
//        }
//
//        @Override
//        public int compare(CorredorAuto t, CorredorAuto t1) {
//            if(tipo_comparacion == DESC){
//                8
//            }
//        }
//        
//        
//        
//        
//    }
}
